﻿#region License statement
// NJamb, a specification and delta-specification DSL
// Copyright (c) 2010-2011, Mark Knell
// Published under the MIT License; all other rights reserved
#endregion

#region using...
using NJamb.Specifications.Delta;
using NJamb.Specifications.Simple;
using NJamb.Specifications.Simple.Singular;
using Stile.Patterns.SelfDescribingPredicates;
using Stile.Patterns.SelfDescribingPredicates.Evaluators;
using Stile.Types.Equality;
#endregion

namespace NJamb.Parser.Subjects.Singular
{
    public static class SingularSubjectExtensions
    {
        public static IDeltaSpecification WillChange<TSubject>(this ISingularSubject<TSubject> singularSubject)
        {
            ICollaboratingSubject<TSubject, ISingularSpecification<TSubject>> collaboratingSubject = singularSubject.Xray;
            var before = new NoOpSpecification<TSubject>(collaboratingSubject);
            VerbTensePair wouldChangeButWasAlways = VerbTensePair.WouldChangeButWasAlways;
            return new DeltaSpecification<TSubject>(before,
                valueFromBefore =>
                new SingularSpecification<TSubject>(collaboratingSubject,
                    new Evaluator<TSubject>(new NoOpExpectedClause<TSubject>(wouldChangeButWasAlways),
                    new ActualClause<TSubject>(wouldChangeButWasAlways),
                    subject => !subject.EqualsOrIsEquallyNull(valueFromBefore))));
        }

        public static IDeltaSpecification WillChangeTo<TSubject>(this ISingularSubject<TSubject> singularSubject, TSubject target)
        {
            ICollaboratingSubject<TSubject, ISingularSpecification<TSubject>> collaboratingSubject = singularSubject.Xray;
            var before = new NoOpSpecification<TSubject>(collaboratingSubject);
            VerbTensePair wouldChangeToButWas = VerbTensePair.WouldChangeToButWas;
            return new DeltaSpecification<TSubject>(before,
                valueFromBefore =>
                new SingularSpecification<TSubject>(collaboratingSubject,
                    new Evaluator<TSubject>(new ExpectedClause<TSubject>(target, Negated.False, wouldChangeToButWas),
                    new ActualClause<TSubject>(wouldChangeToButWas),
                    subject => !subject.EqualsOrIsEquallyNull(valueFromBefore) && subject.EqualsOrIsEquallyNull(target))));
        }

        public static IDeltaSpecification WillNotChange<TSubject>(this ISingularSubject<TSubject> singularSubject)
        {
            ICollaboratingSubject<TSubject, ISingularSpecification<TSubject>> collaboratingSubject = singularSubject.Xray;
            var before = new NoOpSpecification<TSubject>(collaboratingSubject);
            TSubject expected = collaboratingSubject.Get();
            Evaluator<TSubject> evaluator = Expect<TSubject>.ToBeEqualTo(expected, Negated.False);
            ISingularSpecification<TSubject> singularSpecification = collaboratingSubject.Specify(evaluator);
            return new DeltaSpecification<TSubject>(before, singularSpecification);
        }
    }
}
